package corpus;

import baseObjects.Language;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Vector;

public class Indexer extends Thread implements Observable {
    
    public static final String DONE = "DONE";


    private Vector<Observer> observers = new Vector<Observer>();
    private Map<Character, Double> supported = null;
    private double supportedCharCount;
    private String dirName = null;
    private int numOfDirs;
    private int numOfFiles;
    private boolean done;
    private Language lang = null;

    public Indexer(Language l, String CorpusDir) {
        super();
        this.supported = new HashMap<Character, Double>();
        for (Character c : l.getArray()) {
            supported.put(c, 0.0);
        }
        this.dirName = CorpusDir;
        this.done = false;
        this.supportedCharCount = 0;
        this.numOfDirs = this.numOfFiles = 0;
        this.lang = l;

    }

    public Map<Character, Double> getSupported() {
        return supported;
    }

    @Override
    public void run() {
        File f = new File(dirName + System.getProperty("file.separator") + "corpus.properties");
        try {
            updateAll("load from file");
            loadFromFile();
        } catch (FileNotFoundException e) {
            updateAll("indexing corpus");
            index();
            Properties p = new Properties();
            for (Character c : supported.keySet()) {
                p.setProperty(c.toString(), supported.get(c).toString());
            }
            try {
                p.store(new FileOutputStream(new File(dirName + System.getProperty("file.separator") + "corpus.properties")), "");
            } catch (FileNotFoundException ex) {
                updateAll("can't save corpus data file");
            } catch (IOException ex) {
                updateAll("IOEXCEPTION in storing properties file");
            }

        } catch (IOException e) {
            updateAll("IOEXCEPTION ");
        }
        lang.resetProbability();
        lang.updateProbability(supported);
        updateAll(DONE);
    }

    private void index() {
        File files = new File(dirName);
        if (!files.exists()) {
            updateAll("Directory Not Exist or cannot be opend");
        }

        if (files.isDirectory()) {
            readDir(files);
        } else if (files.isFile()) {
            readFile(files);
        } else {
            updateAll("INDEXER : error not a file or directory");
        }

        for (Character c : supported.keySet()) {
            supported.put(c, supported.get(c) / supportedCharCount);
        }

    }

    private void readDir(File files) {
        this.numOfDirs++;
        updateAll("INDEXER : reading Directory " + files.getAbsolutePath());
        File[] fileList = files.listFiles();
        for (File f : fileList) {
            if (f.isDirectory()) {
                if (f.getName().charAt(0) != '.' && !f.isHidden()) {
                    readDir(f);
                }
            } else {
                readFile(f);
            }

        }
    }

    private void readFile(File file) {
        this.numOfFiles++;
        try {
//            BufferedReader br = new BufferedReader(new FileReader(file));
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
            if (!file.getName().equals("corpus.properties")) {
                String line = null;
                int c;
                updateAll("reading file " + file.getName() + " size: " + file.length() / 1024 + " Kb");
                int lineNUm = 0;
                int charNum = 0;
                //while ((line = br.readLine()) != null) {
                while ((c = br.read()) != -1) {
                    char chr = (char) c;
                    if (Character.getType(chr) == Character.LINE_SEPARATOR) {
                        lineNUm++;
                        charNum = 0;
                    } else {
                        if (this.supported.get(chr) != null) {
                            this.supportedCharCount++;
                            this.supported.put(chr, this.supported.get(chr) + 1);
                        } else if (!Character.isWhitespace(chr) && !Character.isSpaceChar(chr)) {
                            updateAll("the char " + chr + "(" + charNum + ") in line " + lineNUm + " is not supported");
                        }
                        charNum++;
                    }
//                    }
//                    lineNUm++;
                }
                updateAll(file.getPath() + " finished");
            }
            br.close();
        } catch (FileNotFoundException e) {
            updateAll("file " + file.getName() + " not found");
        } catch (IOException e) {
            updateAll("I/O error for file " + file.getName());
        }
    }

    public void addObserver(Observer o) {
        observers.add(o);
    }

    public void removeObserver(Observer o) {
        observers.removeElement(o);
    }

    public void updateAll(String s) {
        for (Observer o : observers) {
            o.recive(this, s);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("INDEXER");
        sb.append(System.getProperty("line.separator"));
        sb.append("=======");
        sb.append(System.getProperty("line.separator"));
        for (Character c : supported.keySet()) {
            sb.append(c.toString() + " : " + supported.get(c).toString() + System.getProperty("line.separator"));
        }
        sb.append("num of dirs : " + numOfDirs);
        sb.append(System.getProperty("line.separator"));
        sb.append("num of files : " + numOfFiles);
        sb.append(System.getProperty("line.separator"));
        sb.append("num of chars : " + Double.toString(supportedCharCount));
        sb.append(System.getProperty("line.separator"));


        return sb.toString();
    }

    private void loadFromFile() throws FileNotFoundException, IOException {

        Properties p = new Properties();
        p.load(new FileInputStream(new File(dirName + System.getProperty("file.separator") + "corpus.properties")));
        supported.clear();
        for (Object c : p.keySet()) {
            String key = (String) c;
            supported.put(key.charAt(0), Double.parseDouble(p.getProperty(key)));
        }

    }
}
